﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading;
using System.Net;
using System.IO;
using System.Globalization;
using System.Net.Sockets;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;

namespace GRTVPluginConsole.Utils
{
    public class RealTimeConfig
    {
        public RadarQueryParam queryParam;
        public PictureBox picture;
        private System.Threading.Timer timer;
        public long askWeatherEveryInSecond = 60;
        public string wuAPIKey ="";
        public double ownLatitude;
        public double ownLongitude;
        public string strLastCall;
        // used on each read operation
        private byte[] buf = new byte[8192];
        public byte[] image = new byte[10 * 1024 * 1024]; // 10Mo max
        public int imageSize;
        public bool running;

        private Label lblMessage;
        public RealTimeConfig(Label lblMessage)
        {
            this.lblMessage = lblMessage;
            // Query Param
            queryParam = new RadarQueryParam();
            queryParam.haveRadarInfo = "1".Equals(Program.configuration.iniFile.IniReadValue("WeatherWidget", "image.haveRadarInfo", "1"));
            queryParam.haveSatelliteInfo = "1".Equals(Program.configuration.iniFile.IniReadValue("WeatherWidget", "image.haveSatelliteInfo", "1"));
            queryParam.height = Int32.Parse(Program.configuration.iniFile.IniReadValue("WeatherWidget", "image.height", "300"));
            queryParam.radiusKm = Int32.Parse(Program.configuration.iniFile.IniReadValue("WeatherWidget", "image.radius", "40"));
            queryParam.satelliteType = Program.configuration.iniFile.IniReadValue("WeatherWidget", "image.satellite.type", "sat_vis");
            queryParam.timelabel = "1".Equals(Program.configuration.iniFile.IniReadValue("WeatherWidget", "image.timelabel", "1"));
            queryParam.timelabelX = Int32.Parse(Program.configuration.iniFile.IniReadValue("WeatherWidget", "image.timelabel.x", "50"));
            queryParam.timelabelY = Int32.Parse(Program.configuration.iniFile.IniReadValue("WeatherWidget", "image.timelabel.y", "185"));
            queryParam.width = Int32.Parse(Program.configuration.iniFile.IniReadValue("WeatherWidget", "image.width", "300"));
        }

        public void StopTimer()
        {
            if (timer != null)
            {
                timer.Change(Timeout.Infinite, Timeout.Infinite);
            }
            running = false;
        }
        public void StartOrRestartTimer()
        {
            if (timer != null)
            {
                timer.Change(0, askWeatherEveryInSecond * 1000);
            }
            else
            {
                timer = new System.Threading.Timer(timeTicked, null, 0, askWeatherEveryInSecond * 1000);
            }
            running = true;
        }

        private void timeTicked(object state)
        {
            
            try
            {
                //ownLatitude = 53.15;
                //ownLongitude = -3.34;

                string url = "http://api.wunderground.com/api/" + wuAPIKey;
                if (queryParam.haveRadarInfo && queryParam.haveSatelliteInfo)
                {
                    url += "/radar/satellite/image.gif?rad.noclutter=1";
                    url += "&rad.centerlat=" + ownLatitude.ToString(CultureInfo.InvariantCulture.NumberFormat);
                    url += "&rad.centerlon=" + ownLongitude.ToString(CultureInfo.InvariantCulture.NumberFormat);
                    url += "&rad.radius=" + queryParam.radiusKm + "&rad.radunits=km";
                    url += "&rad.width=" + queryParam.width;
                    url += "&rad.height=" + queryParam.height;
                    url += "&sat.lat=" + ownLatitude.ToString(CultureInfo.InvariantCulture.NumberFormat);
                    url += "&sat.lon=" + ownLongitude.ToString(CultureInfo.InvariantCulture.NumberFormat);
                    url += "&sat.radius=" + queryParam.radiusKm + "&sat.radunits=km";
                    url += "&sat.width=" + queryParam.width;
                    url += "&sat.height=" + queryParam.height;
                    url += "&sat.key=" + queryParam.satelliteType;
                    url += "&sat.gtt=107&sat.proj=me&sat.timelabel=0";
                    url += "&rad.timelabel=" + (queryParam.timelabel?"1":"0");
                    if (queryParam.timelabel) {
                        url += "&rad.timelabel.x=" + queryParam.timelabelX;
                        url += "&rad.timelabel.y=" + queryParam.timelabelY;
                    }
                    url += "&sat.basemap=1";
                }
                else if (queryParam.haveRadarInfo)
                {
                    url += "/radar/image.png?rad.noclutter=1";
                    url += "&centerlat=" + ownLatitude.ToString(CultureInfo.InvariantCulture.NumberFormat);
                    url += "&centerlon=" + ownLongitude.ToString(CultureInfo.InvariantCulture.NumberFormat);
                    url += "&radius=" + queryParam.radiusKm + "&radunits=km";
                    url += "&width=" + queryParam.width;
                    url += "&height=" + queryParam.height;
                    url += "&timelabel=" + (queryParam.timelabel ? "1" : "0");
                    if (queryParam.timelabel)
                    {
                        url += "&timelabel.x=" + queryParam.timelabelX;
                        url += "&timelabel.y=" + queryParam.timelabelY;
                    }
                    url += "&newmaps=1";
                }
                else if (queryParam.haveSatelliteInfo)
                {
                    url += "/satellite/image.png?rad.noclutter=1";
                    url += "&lat=" + ownLatitude.ToString(CultureInfo.InvariantCulture.NumberFormat);
                    url += "&lon=" + ownLongitude.ToString(CultureInfo.InvariantCulture.NumberFormat);
                    url += "&radius=" + queryParam.radiusKm + "&radunits=km";
                    url += "&width=" + queryParam.width;
                    url += "&height=" + queryParam.height;
                    url += "&key=" + queryParam.satelliteType;
                    url += "&gtt=107&proj=me";
                    url += "&timelabel=" + (queryParam.timelabel ? "1" : "0");
                    if (queryParam.timelabel)
                    {
                        url += "&timelabel.x=" + queryParam.timelabelX;
                        url += "&timelabel.y=" + queryParam.timelabelY;
                    }
                    url += "&basemap=1";
                }

                    strLastCall = "" + DateTime.Now;
                    // prepare the web page we will be asking for
                    HttpWebRequest request = (HttpWebRequest)
                        WebRequest.Create(url);

                    //if (request.Proxy != null && Program.Configuration.Proxy != null)
                    //{
                    //    rFactor2WorldWeather.Configurator.Proxy proxyConf = Program.Configuration.Proxy;
                    //    request.Credentials = new NetworkCredential(proxyConf.User, proxyConf.Password, proxyConf.Domain);
                    //    request.Proxy.Credentials = new NetworkCredential(proxyConf.User, proxyConf.Password, proxyConf.Domain);
                    //}

                    // execute the request
                    HttpWebResponse response = (HttpWebResponse)
                        request.GetResponse();
                    if (response.StatusCode != HttpStatusCode.OK)
                    {
                        response.Close();
                        picture.Invoke((MethodInvoker)delegate
                        {
                            lblMessage.Text = "Http error, return code: " + response.StatusCode;
                        });
                        return;
                    }
                // we will read data via the response stream
                    Stream resStream = response.GetResponseStream();
                    StreamReader reader = new StreamReader(resStream);

                    int count = 0;
                    int offsetBuf = 0;
                    do
                    {
                        // fill the buffer with data
                        count = resStream.Read(image, offsetBuf, image.Length - offsetBuf);

                        // make sure we read some data
                        if (count != 0)
                        {
                            offsetBuf += count;
                        }
                    }
                    while (count > 0); // any more data to read?
                
                    response.Close();
                    imageSize = offsetBuf;
                    if (picture != null)
                    {
                        Bitmap realImage = (Bitmap)Image.FromStream(new MemoryStream(image, 0 , imageSize));
                        //realImage.Save("radarTmp.jpg", ImageFormat.Jpeg);
                        //realImage = (Bitmap)Bitmap.FromFile("radarTmp.jpg");
                        using (MemoryStream stream = new MemoryStream())
                        {
                            realImage.Save(stream, ImageFormat.Jpeg);

                            realImage = (Bitmap)Bitmap.FromStream(stream);
                            stream.Close();
                        }
                        float radiusPixel = Math.Min(realImage.Width, realImage.Height) / 2.0f;
                        float centerX = realImage.Width / 2.0f;
                        float centerY = realImage.Height / 2.0f;
                        for (int ix = 0; ix < realImage.Width ; ix++)
                        {
                            for (int iy = 0; iy < realImage.Height; iy++)
                            {
                                if ((ix - centerX) * (ix - centerX) + (iy - centerY) * (iy - centerY) > radiusPixel * radiusPixel)
                                {
//                                    realImage.SetPixel(ix, iy, Color.Transparent);
                                    realImage.SetPixel(ix, iy, Color.Black);
                                }
                            }
                        }


                        using (Graphics g = Graphics.FromImage(realImage))
                        {
                            int offsetRadius = 0;
                            for (int i = 0; i < 5; i++)
                            {
                                offsetRadius = Math.Max(1, (int)(i * radiusPixel / 4));
                                g.DrawArc(Pens.Violet, centerX - offsetRadius, centerY - offsetRadius, offsetRadius * 2, offsetRadius * 2, 0, 360);
                            }
                            Font drawFont = new Font("Arial", 9);
                            SolidBrush drawBrush = new SolidBrush(Color.Violet);

                            // Create rectangle for drawing.
                            float x = 0;
                            float y = 0;
                            float width = 200.0F;
                            float height = 50.0F;
                            RectangleF drawRect = new RectangleF(x, y, width, height);


                            // Set format of string.
                            StringFormat drawFormat = new StringFormat();
                            drawFormat.Alignment = StringAlignment.Near;

                            // Draw string to screen.
                            g.DrawString( (queryParam.radiusKm / 4) + "km", drawFont, drawBrush, drawRect, drawFormat);

                            g.DrawLine(Pens.Violet, 1, 15, 1, 17);
                            g.DrawLine(Pens.Violet, 1 + radiusPixel / 4, 15, 1 + radiusPixel / 4, 17);
                            g.DrawLine(Pens.Violet, 1, 16, 1 + radiusPixel / 4, 16);
                        }
                        string strMess = "Image received: " + DateTime.Now;
                        // send radar image to plugin
                        //realImage.Save("C:/Users/Amphiprion/test.png", ImageFormat.Png);
                        using (MemoryStream stream = new MemoryStream())
                        {
                            realImage.Save(stream, ImageFormat.Jpeg);
                            //// send data
                            byte[] b = stream.ToArray();
                            if (b.Length + 5 <= 100 * 1024)
                            {
                                byte[] bs = new byte[b.Length + 5];
                                bs[0] = 255;
                               
                                Buffer.BlockCopy(b, 0, bs, 5, b.Length);
                               
                                b = BitConverter.GetBytes((int)b.Length);
                                Buffer.BlockCopy(b, 0, bs, 1, b.Length);

                                var client = new UdpClient();
                                IPEndPoint ep = new IPEndPoint(Program.configuration.pluginAddress, Program.configuration.pluginPort);
                                client.Connect(ep);

                                client.Send(bs, bs.Length);
                                client.Close();
                            }
                            else
                            {
                                strMess = "Image too big (>100Ko): " + DateTime.Now;
                            }
                            stream.Close();

                        }

                        picture.Invoke((MethodInvoker)delegate
                            {
                                picture.Invalidate();
                                picture.Image = (Bitmap)realImage.Clone();
                                realImage.Dispose();
                                picture.Refresh();
                                lblMessage.Text = strMess;
                            });
                    }
            }
            catch (Exception eAll)
            {
                picture.Invoke((MethodInvoker)delegate
                {
                    lblMessage.Text = "Unexpected Error: " + eAll.Message;
                });

                return;
            }
        }

    }
}
